﻿using SuperFrame.Charts.Modes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SuperFrame.Charts
{

    public class PhaseChart : Viewbox
    {
        public PhaseChart()
            : base()
        {
            this.Loaded += PhaseChart_Loaded;
        }

        void PhaseChart_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_isLoaded)//加一个属性判断 防止重复加载
            {
                this.Stretch = Stretch.Uniform;
                rootPanel = new Canvas();
                rootPanel.Margin = new Thickness(10);
                rootPanel.Width = 3.5 * Radius;
                rootPanel.Height = 3 * Radius;
                this.Child = rootPanel;
                InitControl();
                _isLoaded = true;
                this.Loaded -= PhaseChart_Loaded;
            }
        }

        #region Propertys
        /// <summary>
        /// 刻度线长度
        /// </summary>
        public double LittleScaleSize
        {
            get { return Radius * 0.05; }
        }

        /// <summary>
        /// 刻度线长度
        /// </summary>
        public double BigScaleSize
        {
            get { return Radius * 0.1; }
        }

        private double uintValue_Little = 6;
        /// <summary>
        /// 刻度尺单位（表示N个单位刻度画一条小刻度线）
        /// </summary>
        public double UintValue_Little
        {
            get { return uintValue_Little; }
            set { uintValue_Little = value; }
        }


        private int unitValue_Big = 5;
        /// <summary>
        /// 表示N个小刻度刻度描一条大刻度线
        /// </summary>
        public int UnitValue_Big
        {
            get { return unitValue_Big; }
            set { unitValue_Big = value; }
        }


        private double lableFontSize = -1;
        /// <summary>
        /// 刻度标签字号
        /// </summary>
        public double LableFontSize
        {
            get
            {
                if (lableFontSize == -1)
                    return Radius * 0.05;
                return lableFontSize;
            }
            set
            {
                try
                {
                    lableFontSize = value;
                }
                catch
                {
                    lableFontSize = -1;
                }
            }
        }
        private double maxValue = 360;

        public double MaxValue
        {
            get { return maxValue; }
            set { maxValue = value; }
        }
        private double minValue = 0;

        public double MinValue
        {
            get { return minValue; }
            set { minValue = value; }
        }

        private double startAngel = 0;
        /// <summary>
        /// 起始角度
        /// </summary>
        public double StartAngel
        {
            get { return startAngel; }
            set
            {
                if (value >= 0)
                    startAngel = value;
                else
                    throw new Exception("起始角度不能小于0°!");
            }
        }

        private double endAngel = 360;
        /// <summary>
        /// 结束角度
        /// </summary>
        public double EndAngel
        {
            get { return endAngel; }
            set
            {
                if (value <= 360)
                    endAngel = value;
                else
                    throw new Exception("起始角度不能大于360°!");
            }
        }
        /// <summary>
        /// 外圆半径
        /// </summary>
        private double radius = 50;

        public double Radius
        {
            get { return radius; }
            set { radius = value; }
        }

        private Brush foreground = new SolidColorBrush(Colors.Black);

        public Brush Foreground
        {
            get { return foreground; }
            set { foreground = value; }
        }
        /// <summary>
        /// 刻度线颜色
        /// </summary>
        private Brush scaleColor = Brushes.Black;
        /// <summary>
        /// 刻度线颜色
        /// </summary>
        public Brush ScaleColor
        {
            get { return scaleColor; }
            set { scaleColor = value; }
        }
        private Brush lableForeGround = Brushes.Black;
        /// <summary>
        /// 刻度标签颜色
        /// </summary>
        public Brush LableForeGround
        {
            get { return lableForeGround; }
            set { lableForeGround = value; }
        }
        private Brush eleAColor = Brushes.Yellow;
        /// <summary>
        /// A相电 颜色
        /// </summary>
        public Brush EleAColor
        {
            get { return eleAColor; }
            set { eleAColor = value; }
        }
        private Brush eleBColor = Brushes.Green;
        /// <summary>
        ///B相电 颜色
        /// </summary>
        public Brush EleBColor
        {
            get { return eleBColor; }
            set { eleBColor = value; }
        }
        private Brush eleCColor = Brushes.Red;
        /// <summary>
        /// C相电 颜色
        /// </summary>
        public Brush EleCColor
        {
            get { return eleCColor; }
            set { eleCColor = value; }
        }

        ArrowsControl acA1 = null;//A相电压指针
        ArrowsControl acA2 = null;//A相电流指针
        ArrowsControl acB1 = null;//B相电压指针
        ArrowsControl acB2 = null;//B相电流指针
        ArrowsControl acC1 = null;//C相电压指针
        ArrowsControl acC2 = null;//C相电流指针

        PhaseInfo pi = null;//右侧的数据

        private PhaseInfoMode eleInfo = new PhaseInfoMode();
        /// <summary>
        /// 数据源实体
        /// </summary>
        public PhaseInfoMode EleInfo
        {
            get { return eleInfo; }
            set { eleInfo = value; }
        }
        private Canvas rootPanel = null;//面板容器

        private bool _isLoaded;
        #endregion


        #region Method
        /// <summary>
        /// 初始化操作
        /// </summary>
        private void InitControl()
        {
            DrawInnerLines();
            DrawingScale();
            DrawingInnerScale();
            DrawingArrows();
            DrawEllipse();
            DrawPhaseInfo();
            DrawLegent();
        }
        /// <summary>
        /// 添加图例
        /// </summary>
        private void DrawLegent()
        {
            LegendControl legent = new LegendControl();
            legent.Width = 3 * Radius;
            legent.Height = 0.6 * Radius;
            legent.SetValue(Canvas.TopProperty, 2.3 * Radius);
            legent.SetValue(Canvas.LeftProperty, 0d);
            legent.LegentInfoList = new List<IntervalMode>() {
                new IntervalMode() { Msg = "A相电压或电流", ColorValue = EleAColor },
                new IntervalMode() { Msg = "B相电压或电流", ColorValue = EleBColor },
                new IntervalMode() { Msg = "C相电压或电流", ColorValue = EleCColor } };
            legent.FontSize = 0.1 * Radius;
            legent.Foreground = Foreground;
            rootPanel.Children.Add(legent);
        }
        /// <summary>
        /// 右侧列表信息
        /// </summary>
        private void DrawPhaseInfo()
        {
            pi = new PhaseInfo();
            pi.EleInfo = this.EleInfo;
            pi.FontSizeValue = Radius * 0.075;
            pi.AForeground = EleAColor;
            pi.BForeground = EleBColor;
            pi.CForeground = EleCColor;
            pi.Foreground = Foreground;
            pi.Height = 2.2 * Radius;
            pi.EleInfo.StateValue = 0;
            pi.Width = 1.5 * Radius;
            pi.SetValue(Canvas.LeftProperty, 2.2 * Radius);
            pi.SetValue(Canvas.TopProperty, 0d);
            rootPanel.Children.Add(pi);
        }
        /// <summary>
        /// 画指针
        /// </summary>
        private void DrawingArrows()
        {
            acA1 = new ArrowsControl();//A 电压指针
            acA1.IsRetrorse = true;
            acA1.OffsetValue = 90d;
            acA1.Width = 0.6 * BigScaleSize;
            acA1.Height = Radius;
            acA1.StrokeColor = EleAColor;
            acA1.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acA1.SetValue(Canvas.TopProperty, 0d);
            Binding bd = new Binding();
            bd.Source = this;
            bd.Path = new PropertyPath("EleInfo.AVoltageAngle");
            acA1.SetBinding(ArrowsControl.AngleValueProperty, bd);
            rootPanel.Children.Add(acA1);

            acA2 = new ArrowsControl();//A 电流指针
            acA2.IsRetrorse = true;
            acA2.OffsetValue = 90d;
            acA2.Width = 0.6 * BigScaleSize;
            acA2.Height = Radius * 2 / 3;
            acA2.StrokeColor = EleAColor;
            acA2.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acA2.SetValue(Canvas.TopProperty, Radius * 1 / 3);
            Binding bd1 = new Binding();
            bd1.Source = this;
            bd1.Path = new PropertyPath("EleInfo.ACurrentAngle");
            acA2.SetBinding(ArrowsControl.AngleValueProperty, bd1);
            rootPanel.Children.Add(acA2);

            acB1 = new ArrowsControl();//B 电压指针
            acB1.IsRetrorse = true;
            acB1.OffsetValue = 90d;
            acB1.Width = 0.6 * BigScaleSize;
            acB1.Height = Radius;
            acB1.StrokeColor = EleBColor;
            acB1.AngleValue = 90;
            acB1.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acB1.SetValue(Canvas.TopProperty, 0d);
            Binding bd2 = new Binding();
            bd2.Source = this;
            bd2.Path = new PropertyPath("EleInfo.BVoltageAngle");
            acB1.SetBinding(ArrowsControl.AngleValueProperty, bd2);
            rootPanel.Children.Add(acB1);

            acB2 = new ArrowsControl();//B 电流指针
            acB2.IsRetrorse = true;
            acB2.OffsetValue = 90d;
            acB2.Width = 0.6 * BigScaleSize;
            acB2.Height = Radius * 2 / 3;
            acB2.StrokeColor = EleBColor;
            acB2.AngleValue = 20;
            acB2.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acB2.SetValue(Canvas.TopProperty, Radius * 1 / 3);
            Binding bd3 = new Binding();
            bd3.Source = this;
            bd3.Path = new PropertyPath("EleInfo.BCurrentAngle");
            acB2.SetBinding(ArrowsControl.AngleValueProperty, bd3);
            rootPanel.Children.Add(acB2);

            acC1 = new ArrowsControl();//C 电压指针
            acC1.IsRetrorse = true;
            acC1.OffsetValue = 90d;
            acC1.Width = 0.6 * BigScaleSize;
            acC1.Height = Radius;
            acC1.StrokeColor = EleCColor;
            acC1.AngleValue = 30;
            acC1.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acC1.SetValue(Canvas.TopProperty, 0d);
            Binding bd4 = new Binding();
            bd4.Source = this;
            bd4.Path = new PropertyPath("EleInfo.CVoltageAngle");
            acC1.SetBinding(ArrowsControl.AngleValueProperty, bd4);
            rootPanel.Children.Add(acC1);

            acC2 = new ArrowsControl();//C 电流指针
            acC2.IsRetrorse = true;
            acC2.OffsetValue = 90d;
            acC2.Width = 0.6 * BigScaleSize;
            acC2.Height = Radius * 2 / 3;
            acC2.StrokeColor = EleCColor;
            acC2.AngleValue = 90;
            acC2.SetValue(Canvas.LeftProperty, Radius - 0.3 * BigScaleSize);
            acC2.SetValue(Canvas.TopProperty, Radius * 1 / 3);
            Binding bd5 = new Binding();
            bd5.Source = this;
            bd5.Path = new PropertyPath("EleInfo.CCurrentAngle");
            acC2.SetBinding(ArrowsControl.AngleValueProperty, bd5);
            rootPanel.Children.Add(acC2);
        }
        /// <summary>
        /// 画中间的十字线
        /// </summary>
        private void DrawInnerLines()
        {
            Point centerPoint = GetCenterPoint();
            Line line1 = new Line();
            line1.X1 = centerPoint.X - Radius;
            line1.Y1 = centerPoint.Y;
            line1.X2 = centerPoint.X + Radius;
            line1.Y2 = centerPoint.Y;
            line1.Stroke = Foreground;
            line1.StrokeThickness = 0.15 * BigScaleSize;
            rootPanel.Children.Add(line1);

            Line line2 = new Line();
            line2.X1 = centerPoint.X;
            line2.Y1 = centerPoint.Y - Radius;
            line2.X2 = centerPoint.X;
            line2.Y2 = centerPoint.Y + Radius;
            line2.Stroke = Foreground;
            line2.StrokeThickness = 0.15 * BigScaleSize;
            rootPanel.Children.Add(line2);
        }
        /// <summary>
        /// 画内圆的刻度线
        /// </summary>
        private void DrawingInnerScale()
        {
            double Sa = StartAngel;// (StartAngel - 270);
            double scalecount = GetScaleCount();
            int start = 0;
            while (start < scalecount + 1)
            {
                double angelValue = GetUnitAngel() * start * (-1);
                Point startPoint = GetScaleLineStartPoint(Sa + angelValue, Radius * 2 / 3);
                Line sLine = new Line();
                sLine.X1 = startPoint.X;
                sLine.Y1 = startPoint.Y;
                sLine.StrokeThickness = 2;
                Point endPoint;
                if (start % UintValue_Little == 0 || start % (UnitValue_Big * UintValue_Little) == 0)
                {
                    endPoint = GetScaleLineEndPoint(Sa + angelValue, LittleScaleSize, Radius * 2 / 3);
                    sLine.Stroke = ScaleColor;
                    sLine.StrokeThickness = 0.15 * LittleScaleSize;
                    sLine.X2 = endPoint.X;
                    sLine.Y2 = endPoint.Y;
                    rootPanel.Children.Add(sLine);
                }
                start++;
            }
        }

        /// <summary>
        /// 画圆
        /// </summary>
        private void DrawEllipse()
        {
            double size = 2 * Radius;//圆大小
            Ellipse outEllip = new Ellipse();
            outEllip.Width = size;
            outEllip.Height = size;
            outEllip.Stroke = Foreground;
            outEllip.StrokeThickness = 0.01 * size;
            rootPanel.Children.Add(outEllip);

            Ellipse outEllip1 = new Ellipse();
            outEllip1.Width = size * 5 / 6;
            outEllip1.Height = size * 5 / 6;
            outEllip1.Stroke = Foreground;
            outEllip1.StrokeThickness = 0.01 * Radius;
            outEllip1.SetValue(Canvas.TopProperty, Radius * 1 / 6);
            outEllip1.SetValue(Canvas.LeftProperty, Radius * 1 / 6);
            outEllip1.StrokeDashArray = new DoubleCollection() { 2 };
            rootPanel.Children.Add(outEllip1);

            Ellipse outEllip2 = new Ellipse();
            outEllip2.Width = size * 2 / 3;
            outEllip2.Height = size * 2 / 3;
            outEllip2.Stroke = Foreground;
            outEllip2.StrokeThickness = 0.015 * Radius;
            outEllip2.SetValue(Canvas.TopProperty, Radius * 1 / 3);
            outEllip2.SetValue(Canvas.LeftProperty, Radius * 1 / 3);
            rootPanel.Children.Add(outEllip2);

            Ellipse InnerEllip = new Ellipse();
            InnerEllip.Width = size * 1 / 3;
            InnerEllip.Height = size * 1 / 3;
            InnerEllip.Stroke = Foreground;
            InnerEllip.StrokeThickness = 0.01 * Radius;
            InnerEllip.SetValue(Canvas.TopProperty, Radius * 2 / 3);
            InnerEllip.SetValue(Canvas.LeftProperty, Radius * 2 / 3);
            InnerEllip.StrokeDashArray = new DoubleCollection() { 2 };
            rootPanel.Children.Add(InnerEllip);

            Ellipse InnerPoint = new Ellipse();
            InnerPoint.Width = size * 1 / 25;
            InnerPoint.Height = size * 1 / 25;
            InnerPoint.Stroke = Foreground;
            InnerPoint.StrokeThickness = Radius * 1 / 25;
            InnerPoint.SetValue(Canvas.TopProperty, Radius * 24 / 25);
            InnerPoint.SetValue(Canvas.LeftProperty, Radius * 24 / 25);
            rootPanel.Children.Add(InnerPoint);
        }
        /// <summary>
        /// 绘制大刻度线
        /// </summary>
        private void DrawingScale()
        {
            double Sa = StartAngel;// (StartAngel - 270);
            double scalecount = GetScaleCount();
            int start = 0;
            Point centerPoint = GetCenterPoint();//圆心坐标
            while (start < scalecount + 1)
            {
                double angelValue = GetUnitAngel() * start * (-1);
                Point startPoint = GetScaleLineStartPoint(Sa + angelValue, Radius);
                Line sLine = new Line();
                sLine.X1 = startPoint.X;
                sLine.Y1 = startPoint.Y;
                sLine.StrokeThickness = 2;
                Point endPoint;
                if (start % (UnitValue_Big * UintValue_Little) == 0)
                {
                    endPoint = GetScaleLineEndPoint(Sa + angelValue, BigScaleSize, Radius);
                    sLine.Stroke = ScaleColor;
                    sLine.StrokeThickness = 0.15 * BigScaleSize;
                    if (!(start == scalecount && angelValue % 360 == 0)) //最后一枚标签位置如果和起始标签重合则不绘制
                    {
                        Point labEndPoint =GetScaleLineEndPoint(Sa + angelValue, BigScaleSize, Radius, true);
                        Label lab = new Label();
                        lab.HorizontalAlignment = HorizontalAlignment.Center;
                        lab.VerticalAlignment = VerticalAlignment.Center;
                        lab.Foreground = LableForeGround;
                        lab.Content = (MinValue + start).ToString() + "°";
                        lab.FontSize = LableFontSize;
                        double CX = labEndPoint.X;
                        double CY = labEndPoint.Y;
                        double tempAngle = MinValue + start;
                        if (0 <= Math.Abs(tempAngle) && Math.Abs(tempAngle) <90)
                        {
                            CX = centerPoint.X + Radius * Math.Cos(tempAngle * Math.PI / 180);
                            CY = centerPoint.Y - Radius * Math.Sin(tempAngle * Math.PI / 180)*1.1- LableFontSize*2;
                        }
                        else if (90 <= Math.Abs(tempAngle) && Math.Abs(tempAngle) <180)
                        {
                            if (90 == Math.Abs(tempAngle))
                            {
                                CX = centerPoint.X - Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180)) - LableFontSize * 2;
                                CY = centerPoint.Y - Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180)) * 1.2;
                            }
                            else
                            {
                                CX = centerPoint.X - Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180))*1.35;
                                CY = centerPoint.Y - Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180)) * 1.25;
                            }
                        }
                        else if (180 <= Math.Abs(tempAngle) && Math.Abs(tempAngle) <270)
                        {
                            if (180 == Math.Abs(tempAngle))
                            {
                                CX = centerPoint.X - Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180)) * 1.3;
                                CY = centerPoint.Y - Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180))- LableFontSize * 2;
                            }
                            else
                            {
                                CX = centerPoint.X - Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180)) * 1.3;
                                CY = centerPoint.Y + Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180));
                            }
                        }
                        else
                        {
                            if (270 == Math.Abs(tempAngle))
                            {
                                CX = centerPoint.X + Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180))- LableFontSize * 3;
                                CY = centerPoint.Y + Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180));
                            }
                            else
                            {
                                CX = centerPoint.X + Math.Abs(Radius * Math.Cos(tempAngle * Math.PI / 180));
                                CY = centerPoint.Y + Math.Abs(Radius * Math.Sin(tempAngle * Math.PI / 180));
                            }
                        }
                        Canvas.SetLeft(lab, CX);
                        Canvas.SetTop(lab, CY);
                        rootPanel.Children.Add(lab);
                    }
                    sLine.X2 = endPoint.X;
                    sLine.Y2 = endPoint.Y;
                    rootPanel.Children.Add(sLine);
                }
                else if (start % UintValue_Little == 0)
                {
                    endPoint = GetScaleLineEndPoint(Sa + angelValue, LittleScaleSize, Radius);
                    sLine.Stroke = ScaleColor;
                    sLine.StrokeThickness = 0.15 * LittleScaleSize;
                    sLine.X2 = endPoint.X;
                    sLine.Y2 = endPoint.Y;
                    rootPanel.Children.Add(sLine);
                }
                start++;
            }
        }
        /// <summary>
        /// 获取刻度线总数
        /// </summary>
        /// <returns></returns>
        private double GetScaleCount()
        {
            return MaxValue - MinValue;
        }

        /// <summary>
        /// 获取坐标点
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetScaleLinePoint(double angel, double value)
        {
            Point center = GetCenterPoint();
            Point startPoint = new Point();
            angel = angel * Math.PI / 180;
            double X = center.X + value * Math.Cos(angel);
            double Y = center.Y + value * Math.Sin(angel);
            startPoint.X = X;
            startPoint.Y = Y;
            return startPoint;
        }

        /// <summary>
        /// 获取刻度线结束点
        /// </summary>
        /// <param name="angel"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private Point GetScaleLineEndPoint(double angel, double value, double radiusValue, bool isLab = false)
        {
            double radius = radiusValue - value;
            if (isLab)
            {
                radius = radiusValue + value + 0.05 * Radius;
            }
            return GetScaleLinePoint(angel, radius);
        }

        /// <summary>
        /// 获取刻度线起始点
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetScaleLineStartPoint(double angel, double radiusValue)
        {
            return GetScaleLinePoint(angel, radiusValue);
        }

        /// <summary>
        /// 获取圆心坐标
        /// </summary>
        /// <returns></returns>
        private Point GetCenterPoint()
        {
            return new Point(Radius, Radius);
        }

        /// <summary>
        /// 获取单位刻度所占的角度
        /// </summary>
        /// <returns></returns>
        private double GetUnitAngel()
        {
            double scaleCount = GetScaleCount();
            double angelCount = Math.Abs(EndAngel - StartAngel);
            double unitAngel = angelCount / scaleCount;
            return unitAngel;
        }
        #endregion

    }
}
